// SPDX-License-Identifier: MIT
// SPDX-FileCopyrightText: 2022 Ivan Baidakou

#include "rotor-light/queue.hpp"

using namespace rotor_light;

ItemQueueBase::ItemQueueBase(size_t item_size_, size_t items_count_)
    : buff_ptr(nullptr), item_size{static_cast<index_t>(item_size_)},
      items_count{static_cast<index_t>(items_count_)}, free_index{undef},
      occupied_index{undef} {}

void ItemQueueBase::post_constructor(char *buff_) {
  buff_ptr = buff_;
  free_index = 0;
}

Message *ItemQueueBase::next() {
  if (occupied_index != undef) {
    auto ptr = buff_ptr + item_size * occupied_index;
    return reinterpret_cast<Message *>(ptr);
  }
  return nullptr;
}

void ItemQueueBase::release(Message *) {
  occupied_index = (occupied_index + 1) % items_count;
  if (occupied_index == free_index) {
    occupied_index = undef;
  }
}

ItemGuard &ItemGuard::operator=(ItemGuard &&other) {
  std::swap(item_queue, other.item_queue);
  std::swap(message, other.message);
  return *this;
}

void ItemGuard::reset() {
  item_queue->release(message);
  message = nullptr;
}

ItemGuard::~ItemGuard() {
  if (message) {
    reset();
  }
}

QueueBase::QueueBase(ItemQueueBase **queues_, size_t queue_count_)
    : queues{queues_}, queue_count{static_cast<uint8_t>(queue_count_)} {}

ItemGuard QueueBase::next() {
  for (int i = static_cast<int>(queue_count - 1); i >= 0; --i) {
    auto &queue = queues[i];
    auto r = queue->next();
    if (r) {
      return {r, queue};
    }
  }
  return {};
}
